package com.share.common.utils;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.Security;

/**
 * SM1 是硬件对称加密,SM4是常规的对称加密   密钥都是要由系统生成,而不是随机指定
 * SM2 是摘要
 * SM3 是RAS
 */
public class SMUtil {
    private static final Charset UTF_8 = StandardCharsets.UTF_8;
    private static final String ALGORITHM_SM4 = "SM4";
    private static final String ALGORITHM_ECB_PKCS5PADDING = "SM4/ECB/PKCS5Padding";

    private static final int DEFAULT_KEY_SIZE = 128; //SM4算法目前只支持128位（即密钥16字节）

    static {
        // 防止内存中出现多次BouncyCastleProvider的实例
        if (null == Security.getProvider(BouncyCastleProvider.PROVIDER_NAME)) {
            Security.addProvider(new BouncyCastleProvider());
        }
    }


    //生成sm4的密钥key并转换为hex字符串串
    public static String genHexKey() throws Exception {
        KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_SM4, BouncyCastleProvider.PROVIDER_NAME);
        kg.init(DEFAULT_KEY_SIZE, new SecureRandom());
        byte[] byteKey = kg.generateKey().getEncoded();
        String strKey = HexUtil.byte2hex(byteKey);
        return strKey;
    }

    //加密
    public static byte[] encrypt(byte[] data, String hex_sm4_key) throws Exception {
        return sm4(data, hex_sm4_key, Cipher.ENCRYPT_MODE);
    }

    //加密---返回hex字符串
    public static String encrypt2HexStr(String data, String hex_sm4_key) throws Exception {
        byte[] bytes = data.getBytes(UTF_8);
        byte[] result = encrypt(bytes, hex_sm4_key);
        return HexUtil.byte2hex(result);
    }

    //解密
    public static byte[] decrypt(byte[] data, String hex_sm4_key) throws Exception {
        byte[] result = sm4(data, hex_sm4_key, Cipher.DECRYPT_MODE);
        return result;
    }

    //解密
    public static String decrypt(String hexStr, String hex_sm4_key) throws Exception {
        byte[] bytes = HexUtil.hexStr2Bytes(hexStr);
        byte[] result = decrypt(bytes, hex_sm4_key);
        String s = new String(result, UTF_8);
        return s;
    }

    //解密
    public static String decrypt2HexStr(String hexStr, String hex_sm4_key) throws Exception {
        byte[] bytes = HexUtil.hexStr2Bytes(hexStr);
        byte[] result = decrypt(bytes, hex_sm4_key);
        return HexUtil.byte2hex(result);
    }

    /**
     * SM4对称加解密
     *
     * @param byteText  明文（加密模式）或密文（解密模式）
     * @param hexStrkey 密钥
     * @param mode      Cipher.ENCRYPT_MODE - 加密；Cipher.DECRYPT_MODE - 解密
     * @return 密文（加密模式）或明文（解密模式）
     * @throws Exception 加解密异常
     */
    private static byte[] sm4(byte[] byteText, String hexStrkey, int mode) throws Exception {
        byte[] byteKey = HexUtil.hexStr2Bytes(hexStrkey);//key是hex字符串
        Cipher cipher = Cipher.getInstance(ALGORITHM_ECB_PKCS5PADDING, BouncyCastleProvider.PROVIDER_NAME);
        cipher.init(mode, new SecretKeySpec(byteKey, ALGORITHM_SM4));
        byte[] bytes = cipher.doFinal(byteText);
        return bytes;
    }

    public static void main(String[] args) throws Exception {
        String key = genHexKey();
        System.out.println(key);
        String text = "01";
        String encrypt = encrypt2HexStr(text, key);
        System.out.println(encrypt);
        String decrypt = decrypt(encrypt, key);
        System.out.println(decrypt);
    }
}
